<?php

/**
 * NOTICE OF LICENSE
 *
 * THIS SOURCE FILE IS PART OF EVEBIT'S PRIVATE PROJECT.
 * 
 * DO NOT USE THIS FILE IN OTHER PLACE.
 *
 * @category    EveBit_Library
 * @package     Application
 * @author      Cheng Wei <berlios.o@gmail.com>
 * @version     $$Id: Observer.php 130 2011-03-18 03:10:02Z cheng.wei $$
 * @copyright   Copyright (c) 2008 Evebit Inc. China (http://www.evebit.com)
 */

/**
 * Event observer
 * 
 * @package     Application
 * @author      Cheng Wei <berlios.o@gmail.com>
 * @version     $$Id: Observer.php 130 2011-03-18 03:10:02Z cheng.wei $$
 */
final class Evebit_Event_Observer extends Varien_Object {
	/**
	 * @var Zend_Log
	 */
	protected $logger = null;
	
	/**
	 * @var array
	 */
	protected $events = null;
	
	/**
	 * limit to one instance
	 */
	public function __construct() {
		if (Zend_Registry::isRegistered('Evebit_Event_Observer')) {
			throw new Zend_Exception("Event observer could only have one instance");
		}
		
		$this->logger = Evebit_Application::app()->getLog();
	}
	
	/**
	 * dispatch event
	 * 
	 * @param Evebit_Event $event
	 */
	public function dispatch(Evebit_Event $event) {
		$code = $event->getCode();
		if ($this->logger)
			$this->logger->info(sprintf("Event: %s", $code));
		if (isset($this->events[$code])) {
			$count = count($this->events[$code]);
			for($i = 0; $i < $count; $i++) {
				if (!isset($this->events[$code][$i]['ob'])) {
					$type = $this->events[$code][$i]['observer'];
					if (!@class_exists($type)) {
						$this->events[$code][$i]['ob'] = false;
						if ($this->logger)
							$this->logger->err(
								sprintf("Event: observer '%s' for %s not exists", $type, 
									$code));
					} else {
						$ob = $this->events[$code][$i]['ob'] = new $type();
						$method = $this->events[$code][$i]['callback'];
						if (!is_callable(array($ob, $method))) {
							$this->events[$code][$i]['ob'] = false;
							if ($this->logger)
								$this->logger->err(
									sprintf(
										"Event: observer '%s' not contain method '%s' for %s not exists", 
										$type, $method, $code));
						}
					}
				}
				if ($this->events[$code][$i]['ob']) {
					$ob = $this->events[$code][$i]['ob'];
					$method = $this->events[$code][$i]['callback'];
					call_user_func_array(array($ob, $method), $event->getArguments());
				}
			}
		}
	}
	
	/**
	 * Init event registry
	 * 
	 * @param array $config
	 */
	public function init(array $config) {
		// if ($this->logger) $this->logger->info("Event: init events");
		

		foreach ($config as $code => $observers) {
			if (!isset($this->events[$code])) {
				$this->events[$code] = array();
			}
			foreach ($observers as $observer) {
				if (isset($observer['observer']) && isset($observer['callback'])) {
					$this->events[$code][] = array(
							'observer'=> $observer['observer'], 
							'callback'=> $observer['callback']);
				}
			}
		}
		
	// if ($this->logger) $this->logger->debug($this->events);
	}
	
	/**
	 * Handle event
	 */
	public function handle() {
		if ($this->logger)
			$this->logger->setEventItem();
	}
	
	/**
	 * @return Evebit_Event_Observer
	 */
	public static function getInstance() {
		if (!Zend_Registry::isRegistered('Evebit_Event_Observer')) {
			$observe = new Evebit_Event_Observer();
			Zend_Registry::set('Evebit_Event_Observer', $observe);
		}
		return Zend_Registry::get('Evebit_Event_Observer');
	}

}